//+------------------------------------------------------------------+
//|                                               TrendAnalysis.mqh |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link      ""
#property version   "1.00"
#property strict

// 趋势类型枚举
enum ENUM_TREND_TYPE {
    TREND_UP,        // 上升趋势
    TREND_DOWN,      // 下降趋势
    TREND_SIDEWAYS   // 盘整趋势
};

// 趋势结构
struct Trend {
    ENUM_TREND_TYPE type;     // 趋势类型
    int startBar;             // 起始K线
    int endBar;               // 结束K线
    double startPrice;        // 起始价格
    double endPrice;          // 结束价格
    double strength;          // 趋势强度
    bool isActive;            // 是否活跃
};

// Market state enumeration
enum ENUM_MARKET_STATE {
    MARKET_STATE_TRENDING_UP,
    MARKET_STATE_TRENDING_DOWN,
    MARKET_STATE_RANGING,
    MARKET_STATE_VOLATILE,
    MARKET_STATE_UNKNOWN
};

// Trend analysis class
class CTrendAnalysis {
private:
    Trend m_trends[];         // 趋势数组
    int m_trendCount;         // 趋势计数
    int m_currentTrend;       // 当前趋势索引
    
    // 趋势识别参数
    int m_maPeriod;           // 移动平均线周期
    int m_adxPeriod;          // ADX周期
    double m_adxThreshold;    // ADX阈值
    double m_trendThreshold;  // 趋势阈值
    
    // 指标句柄
    int m_maHandle;           // 移动平均线句柄
    int m_adxHandle;          // ADX句柄
    int m_rsiHandle;
    int m_bbHandle;
    ENUM_MARKET_STATE m_marketState;
    double m_volatilityThreshold;
    
public:
    // Constructor
    CTrendAnalysis() {
        m_trendCount = 0;
        m_currentTrend = -1;
        m_maPeriod = 20;          // 默认MA周期
        m_adxPeriod = 14;         // 默认ADX周期
        m_adxThreshold = 25.0;    // 默认ADX阈值
        m_trendThreshold = 0.5;   // 默认趋势阈值
        m_maHandle = INVALID_HANDLE;
        m_rsiHandle = INVALID_HANDLE;
        m_bbHandle = INVALID_HANDLE;
        m_marketState = MARKET_STATE_UNKNOWN;
        m_volatilityThreshold = 1.5;
    }
    
    // Initialize trend analysis
    bool Initialize(int maPeriod = 20, int adxPeriod = 14, double adxThreshold = 25.0, double trendThreshold = 0.5) {
        m_maPeriod = maPeriod;
        m_adxPeriod = adxPeriod;
        m_adxThreshold = adxThreshold;
        m_trendThreshold = trendThreshold;
        
        // Create MA indicator
        m_maHandle = iMA(Symbol(), PERIOD_CURRENT, m_maPeriod, 0, MODE_SMA, PRICE_CLOSE);
        if(m_maHandle == INVALID_HANDLE) {
            Print("Failed to create MA indicator");
            return false;
        }
        
        // Create ADX indicator
        m_adxHandle = iADX(Symbol(), PERIOD_CURRENT, m_adxPeriod);
        if(m_adxHandle == INVALID_HANDLE) {
            Print("Failed to create ADX indicator");
            return false;
        }
        
        // Create RSI indicator
        m_rsiHandle = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE);
        if(m_rsiHandle == INVALID_HANDLE) {
            Print("Failed to create RSI indicator");
            return false;
        }
        
        // Create Bollinger Bands indicator
        m_bbHandle = iBands(Symbol(), PERIOD_CURRENT, 20, 0, 2, PRICE_CLOSE);
        if(m_bbHandle == INVALID_HANDLE) {
            Print("Failed to create Bollinger Bands indicator");
            return false;
        }
        
        return true;
    }
    
    // Clean up
    void Cleanup() {
        if(m_maHandle != INVALID_HANDLE) {
            IndicatorRelease(m_maHandle);
            m_maHandle = INVALID_HANDLE;
        }
        if(m_rsiHandle != INVALID_HANDLE) {
            IndicatorRelease(m_rsiHandle);
            m_rsiHandle = INVALID_HANDLE;
        }
        if(m_bbHandle != INVALID_HANDLE) {
            IndicatorRelease(m_bbHandle);
            m_bbHandle = INVALID_HANDLE;
        }
    }
    
    // Get trend direction
    int GetTrendDirection() {
        if(m_maHandle == INVALID_HANDLE) return 0;
        
        double maCurrent = GetMAValue(0);
        double maPrevious = GetMAValue(1);
        
        if(maCurrent > maPrevious) return 1;    // Uptrend
        if(maCurrent < maPrevious) return -1;   // Downtrend
        return 0;                               // No clear trend
    }
    
    // Get trend strength
    double GetTrendStrength() {
        if(m_maHandle == INVALID_HANDLE) return 0;
        
        int upBars = 0;
        int totalBars = m_adxPeriod;
        
        for(int idx = 0; idx < totalBars; idx++) {
            double adxCurrent = GetADXValue(idx);
            double adxPrevious = GetADXValue(idx + 1);
            
            if(adxCurrent > adxPrevious) upBars++;
        }
        
        return (double)upBars / totalBars;
    }
    
    // Check if trend is strong enough
    bool IsTrendStrong() {
        return GetTrendStrength() >= m_trendThreshold;
    }
    
    // Check volume confirmation
    bool CheckVolumeConfirmation(int period) {
        double currentVolume = iVolume(Symbol(), PERIOD_CURRENT, 0);
        double avgVolume = 0;
        
        // Calculate average volume
        for(int idx = 1; idx <= period; idx++) {
            avgVolume += iVolume(Symbol(), PERIOD_CURRENT, idx);
        }
        avgVolume /= period;
        
        // Check if current volume is higher than average
        return currentVolume > avgVolume;
    }
    
    // Detect market state
    ENUM_MARKET_STATE DetectMarketState() {
        if(m_maHandle == INVALID_HANDLE || m_rsiHandle == INVALID_HANDLE || m_bbHandle == INVALID_HANDLE)
            return MARKET_STATE_UNKNOWN;
            
        // Get trend direction
        int trendDirection = GetTrendDirection();
        
        // Get RSI value
        double rsiValue = GetRSIValue(0);
        
        // Get Bollinger Bands values
        double bbUpper[], bbMiddle[], bbLower[];
        ArraySetAsSeries(bbUpper, true);
        ArraySetAsSeries(bbMiddle, true);
        ArraySetAsSeries(bbLower, true);
        
        bool bbCopySuccess = (CopyBuffer(m_bbHandle, 1, 0, 1, bbUpper) == 1 &&
                            CopyBuffer(m_bbHandle, 0, 0, 1, bbMiddle) == 1 &&
                            CopyBuffer(m_bbHandle, 2, 0, 1, bbLower) == 1);
                            
        if(!bbCopySuccess) {
            return MARKET_STATE_UNKNOWN;
        }
        
        // Calculate volatility
        double volatility = (bbUpper[0] - bbLower[0]) / bbMiddle[0];
        
        // Get current price
        double currentPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID);
        
        // Determine market state
        if(volatility > m_volatilityThreshold) {
            m_marketState = MARKET_STATE_VOLATILE;
        }
        else if(trendDirection == 1 && rsiValue > 50) {
            m_marketState = MARKET_STATE_TRENDING_UP;
        }
        else if(trendDirection == -1 && rsiValue < 50) {
            m_marketState = MARKET_STATE_TRENDING_DOWN;
        }
        else if(currentPrice > bbLower[0] && currentPrice < bbUpper[0]) {
            m_marketState = MARKET_STATE_RANGING;
        }
        else {
            m_marketState = MARKET_STATE_UNKNOWN;
        }
        
        return m_marketState;
    }
    
    // Get current market state
    ENUM_MARKET_STATE GetMarketState() {
        return m_marketState;
    }
    
    // Check if market is suitable for trading
    bool IsMarketSuitable() {
        ENUM_MARKET_STATE state = DetectMarketState();
        
        // Don't trade in volatile or unknown market states
        if(state == MARKET_STATE_VOLATILE || state == MARKET_STATE_UNKNOWN)
            return false;
            
        return true;
    }
    
    // Analyze price data
    bool AnalyzePriceData(const double &high[], const double &low[], const double &close[], int count) {
        if(count < m_maPeriod) return false;
        
        // Reset trends array
        ArrayResize(m_trends, 0);
        m_trendCount = 0;
        m_currentTrend = -1;
        
        // Get indicator data
        double maBuffer[];
        double adxBuffer[];
        double plusDI[];
        double minusDI[];
        
        ArraySetAsSeries(maBuffer, true);
        ArraySetAsSeries(adxBuffer, true);
        ArraySetAsSeries(plusDI, true);
        ArraySetAsSeries(minusDI, true);
        
        if(CopyBuffer(m_maHandle, 0, 0, count, maBuffer) != count) return false;
        if(CopyBuffer(m_adxHandle, 0, 0, count, adxBuffer) != count) return false;
        if(CopyBuffer(m_adxHandle, 1, 0, count, plusDI) != count) return false;
        if(CopyBuffer(m_adxHandle, 2, 0, count, minusDI) != count) return false;
        
        // Analyze trends
        for(int idx = m_maPeriod; idx < count; idx++) {
            if(IsTrendChange(maBuffer, adxBuffer, plusDI, minusDI, idx)) {
                AddTrend(high, low, close, maBuffer, adxBuffer, plusDI, minusDI, idx);
            }
        }
        
        return m_trendCount > 0;
    }
    
    // Check if trend is changing
    bool IsTrendChange(const double &maBuffer[], const double &adxBuffer[], 
                      const double &plusDI[], const double &minusDI[], int barIndex) {
        // Check ADX strength
        if(adxBuffer[barIndex] < m_adxThreshold) return false;
        
        // Check trend direction
        bool isUpTrend = plusDI[barIndex] > minusDI[barIndex];
        bool wasUpTrend = plusDI[barIndex + 1] > minusDI[barIndex + 1];
        
        return isUpTrend != wasUpTrend;
    }
    
    // Add new trend
    void AddTrend(const double &high[], const double &low[], const double &close[],
                 const double &maBuffer[], const double &adxBuffer[],
                 const double &plusDI[], const double &minusDI[], int barIndex) {
        Trend trend;
        trend.startBar = barIndex;
        trend.startPrice = close[barIndex];
        trend.isActive = true;
        
        // Determine trend type
        if(plusDI[barIndex] > minusDI[barIndex]) {
            trend.type = TREND_UP;
        } else if(plusDI[barIndex] < minusDI[barIndex]) {
            trend.type = TREND_DOWN;
        } else {
            trend.type = TREND_SIDEWAYS;
        }
        
        // Calculate trend strength
        trend.strength = adxBuffer[barIndex] / 100.0;
        
        // Add to trends array
        ArrayResize(m_trends, m_trendCount + 1);
        m_trends[m_trendCount++] = trend;
        m_currentTrend = m_trendCount - 1;
    }
    
    // Update current trend
    bool UpdateCurrentTrend(const double &high[], const double &low[], const double &close[],
                          const double &maBuffer[], const double &adxBuffer[],
                          const double &plusDI[], const double &minusDI[], int barIndex) {
        if(m_currentTrend < 0) return false;
        
        Trend &currentTrend = m_trends[m_currentTrend];
        
        // Update trend end position
        currentTrend.endBar = barIndex;
        currentTrend.endPrice = close[barIndex];
        
        // Check if trend is ending
        if(IsTrendChange(maBuffer, adxBuffer, plusDI, minusDI, barIndex)) {
            currentTrend.isActive = false;
            return true;
        }
        
        return false;
    }
    
    // Get current trend
    bool GetCurrentTrend(Trend &trend) {
        if(m_currentTrend < 0 || m_currentTrend >= m_trendCount) return false;
        
        trend = m_trends[m_currentTrend];
        return true;
    }
    
    // Get trend count
    int GetTrendCount() {
        return m_trendCount;
    }
    
    // Get trend at specified index
    bool GetTrend(int index, Trend &trend) {
        if(index < 0 || index >= m_trendCount) return false;
        
        trend = m_trends[index];
        return true;
    }
    
    // Predict trend continuation
    bool PredictTrendContinuation(Trend &predictedTrend) {
        if(m_currentTrend < 0) return false;
        
        Trend currentTrend = m_trends[m_currentTrend];
        
        // Predict trend continuation
        predictedTrend = currentTrend;
        predictedTrend.startBar = currentTrend.endBar;
        predictedTrend.startPrice = currentTrend.endPrice;
        
        // Predict trend strength
        predictedTrend.strength = currentTrend.strength * 0.8; // Assume trend strength will slightly weaken
        
        predictedTrend.isActive = true;
        return true;
    }
    
    // Validate trend strength
    bool ValidateTrendStrength() {
        if(m_currentTrend < 0) return false;
        
        Trend currentTrend = m_trends[m_currentTrend];
        
        // Check if trend strength is sufficient
        return currentTrend.strength >= m_trendThreshold;
    }
    
    // Clean up old trends
    void CleanupOldTrends(int maxAge) {
        for(int idx = m_trendCount - 1; idx >= 0; idx--) {
            if(!m_trends[idx].isActive && 
               (m_trends[idx].endBar - m_trends[idx].startBar) > maxAge) {
                // Remove old trend
                for(int jdx = idx; jdx < m_trendCount - 1; jdx++) {
                    m_trends[jdx] = m_trends[jdx + 1];
                }
                m_trendCount--;
            }
        }
    }
    
private:
    // Get MA value
    double GetMAValue(int shift) {
        double maBuffer[];
        ArraySetAsSeries(maBuffer, true);
        
        bool maCopySuccess = (CopyBuffer(m_maHandle, 0, shift, 1, maBuffer) == 1);
        if(!maCopySuccess) {
            return 0.0;
        }
        
        return maBuffer[0];
    }
    
    // Get ADX value
    double GetADXValue(int shift) {
        double adxBuffer[];
        ArraySetAsSeries(adxBuffer, true);
        
        bool adxCopySuccess = (CopyBuffer(m_adxHandle, 0, shift, 1, adxBuffer) == 1);
        if(!adxCopySuccess) {
            return 0.0;
        }
        
        return adxBuffer[0];
    }
    
    // Get RSI value
    double GetRSIValue(int shift) {
        double rsiBuffer[];
        ArraySetAsSeries(rsiBuffer, true);
        
        bool rsiCopySuccess = (CopyBuffer(m_rsiHandle, 0, shift, 1, rsiBuffer) == 1);
        if(!rsiCopySuccess) {
            return 0.0;
        }
        
        return rsiBuffer[0];
    }
}; 